
比较下面的类模板:

\begin{lstlisting}[style=styleCXX]
template<typename T, int N>
class ArrayInClass {
	public:
	T array[N];
};
\end{lstlisting}

使用普通类:

\begin{lstlisting}[style=styleCXX]
class DoubleArrayInClass {
	public:
	double array[10];
};
\end{lstlisting}

如果将参数T和N分别替换为double和10，则后者在本质上等价于前者。C++中，这个替换可表示为

\begin{lstlisting}[style=styleCXX]
ArrayInClass<double,10>
\end{lstlisting}

注意模板名称后面是如何用尖括号将模板参数括起来的。

不管这些实参本身是否依赖于模板形参，模板名后跟尖括号中的实参的组合称为模板标识。

可以像使用非模板一样使用这个名称。例如:

\begin{lstlisting}[style=styleCXX]
int main()
{
	ArrayInClass<double,10> ad;
	ad.array[0] = 1.0;
}
\end{lstlisting}

区分模板形参和模板实参很重要。简而言之，“参数由实参初始化”。

\begin{tcolorbox}[colback=webgreen!5!white,colframe=webgreen!75!black]
\hspace*{0.75cm}学术界中，参数有时称为实际参数，而声明参数称为形式参数。
\end{tcolorbox}

或者更准确地说:

\begin{itemize}
\item 
模板参数是那些列在模板声明或定义中的关键字Template之后的参数(示例中是T和N)。

\item 
模板实参是替代模板形参的项(示例中是double和10)。与模板形参不同，模板实参可以不仅仅是“名称”。
\end{itemize}

当使用模板标识表示时，模板实参对模板形参是显式替换的。但在许多情况下，替换是隐式的(例如，如果模板形参被默认实参替换)。

基本原则是，模板参数必须在编译时确定。这个需求对于模板实体运行时成本有巨大的好处。因为模板形参最终会被编译时的值替代，所以其本身可以形成编译时表达式。这在ArrayInClass模板中可以用来调整成员数组的大小。数组的大小必须是一个常量表达式，而模板参数N刚好符合此条件。

可以进一步推进这种方式:因为模板形参是编译时实体，所以也可以用来创建有效的模板形参。下面是一个例子:

\begin{lstlisting}[style=styleCXX]
template<typename T>
class Dozen {
	public:
	ArrayInClass<T,12> contents;
};
\end{lstlisting}

本例中，名称T既是模板形参，又是模板实参。因此，可以使用一种机制从更简单的模板构建更复杂的模板。当然，这与组装类型和函数的机制没有区别。


























